package io.gitee.cofenghen.jdbctempleplus.core;

import io.gitee.cofenghen.jdbctempleplus.BaseJdbcTemplePlus;
import io.gitee.cofenghen.jdbctempleplus.exception.OrmException;
import io.gitee.cofenghen.jdbctempleplus.support.EntityMeta;
import io.gitee.cofenghen.jdbctempleplus.support.EntityParser;
import io.gitee.cofenghen.jdbctempleplus.support.QueryCondition;
import jdk.jshell.spi.ExecutionControl;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class OrmTemplate extends BaseJdbcTemplePlus implements IOrmTemplate {

    public   BaseJdbcTemplePlus ado()
    {
            return  this;
    }
    @Override
    public <T> int insert(T entity)  throws OrmException {
        EntityMeta meta = EntityParser.parse(entity.getClass());
        String sql = buildInsertSql(meta);
        Map<String, Object> params = buildParams(entity, meta);
        return  this.update(sql, params);

    }

    @SneakyThrows
    @Override
    public <T> int batchInsert(List<T> entities) throws OrmException {
        throw  new ExecutionControl.NotImplementedException("未实现！");

    }

    @Override
    public <T> T queryById(Class<T> entityClass,Object id) throws OrmException {

        //读取主键
        EntityMeta meta = EntityParser.parse(entityClass);
        String sql = buildSelectSqlByPrimaryKey(meta);
        Map<String, Object> params =new HashMap<>();
        params.put(meta.getPrimaryKeyFieldName(),id);
        return  this.selectOne(sql, params,entityClass);
      //  return  Optional.of( this.selectOne(sql, params,entityClass));

    }
   public  <T>  List<T> query(Class<T> entityClass, QueryCondition<T> queryCondition)
   {
       EntityMeta meta = EntityParser.parse(entityClass);
       var  sqlParameterSource = queryCondition.toSql();

       String sql="select * from "+meta.getTableName();
        var sqlwhere =sqlParameterSource.getSqlwhere();
        if (!sqlwhere.isEmpty())
        {
            sql+=" where "+sqlwhere;
        }
        return  this.select(sql,sqlParameterSource.getParamsMap(),entityClass);



   }

   public      <T>  QueryCondition<T>  query(Class<T> entityClass)
   {

       return new QueryCondition<T>();
   }
    @Override
    public <T> int updateById(Object id, T entity) {

        EntityMeta meta = EntityParser.parse(entity.getClass());
        String sql = buildUpdateSqlById(meta);
        Map<String, Object> params = buildParams(entity, meta);
        return  this.update(sql, params);

    }

    @Override
    public <T> int deleteById(Class<T> entityClass,Object id) {
        EntityMeta meta = EntityParser.parse(entityClass);
        String sql = buildDeleteSqlByPrimaryKey(meta);
        Map<String, Object> params =  new HashMap<>();
        params.put(meta.getPrimaryKeyFieldName(),id);
        return  this.update(sql, params);
    }



    private <T> String buildInsertSql(EntityMeta meta) {
        StringBuilder sql = new StringBuilder("INSERT INTO ");
        sql.append(meta.getTableName()).append(" (");
        meta.getFieldMetas().forEach((fieldName, fieldMeta) -> {
            sql.append(fieldMeta.getColumnName()).append(", ");
        });
        sql.setLength(sql.length() - 2); // 去掉最后的 ", "
        sql.append(") VALUES (");
        meta.getFieldMetas().forEach((fieldName, fieldMeta) -> {
            sql.append(":").append(fieldMeta.getColumnName()).append(", ");
        });
        sql.setLength(sql.length() - 2); // 去掉最后的 ", "
        sql.append(")");
        return sql.toString();
    }

    private <T> Map<String, Object> buildParams(T entity, EntityMeta meta) {
        Map<String, Object> params = new HashMap<>();
        meta.getFieldMetas().forEach((fieldName, fieldMeta) -> {
            try {
                Field field = entity.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                params.put(fieldMeta.getColumnName(),field.get(entity) );
            } catch (Exception e) {
                throw new OrmException("Failed to build insert params", e);
            }
        });
        return params;
    }


    // 构建更新 SQL
    private <T> String buildUpdateSqlById(EntityMeta meta) {

        if (meta.getPrimaryKeyFieldName().isEmpty())
            throw  new OrmException("表"+meta.getTableName()+"未设置主键,不允许按主键执行Update");
        StringBuilder sql = new StringBuilder("UPDATE ");
        sql.append(meta.getTableName()).append(" SET ");
        meta.getFieldMetas().forEach((fieldName, fieldMeta) -> {
            if (!fieldName.equals(meta.getPrimaryKeyFieldName())) { // 排除主键字段
                sql.append(fieldMeta.getColumnName()).append(" = :").append(fieldMeta.getColumnName()).append(", ");
            }
        });
        sql.setLength(sql.length() - 2); // 去掉最后的 ", "
        sql.append(" WHERE ").append(meta.getPrimaryKeyFieldName()).append(" = :").append(meta.getPrimaryKeyFieldName());
        return sql.toString();
    }

    // 构建更新 SQL
    private <T> String buildSelectSqlByPrimaryKey(EntityMeta meta) {

        if (meta.getPrimaryKeyFieldName().isEmpty())
            throw  new OrmException("表"+meta.getTableName()+"未设置主键,不允许按主键执行select by PrimaryKey");
        StringBuilder sql = new StringBuilder("Select *  from ");
        sql.append(meta.getTableName()) ;

        sql.append(" WHERE ").append(meta.getPrimaryKeyFieldName()).append(" = :").append(meta.getPrimaryKeyFieldName());



        return sql.toString();
    }

    // 构建更新 SQL
    private <T> String buildDeleteSqlByPrimaryKey(EntityMeta meta) {

        if (meta.getPrimaryKeyFieldName().isEmpty())
            throw  new OrmException("表"+meta.getTableName()+"未设置主键,不允许按主键执行select by PrimaryKey");
        StringBuilder sql = new StringBuilder("Delete ");
        sql.append(meta.getTableName()) ;

        sql.append(" WHERE ").append(meta.getPrimaryKeyFieldName()).append(" = :").append(meta.getPrimaryKeyFieldName());



        return sql.toString();
    }
}
